from functools import wraps


# function decorator
def func_decorator_a(func):
    @wraps(func)  # 保留原始函数信息，方便调试
    def wrapper(*args, **kwargs):
        print("func_decorator_a")
        return func(*args, **kwargs)

    return wrapper


@func_decorator_a
def func(a):
    print("func")
    return a


func(1)
print("-------------")


# class decorator
class ClassDecoratorA:
    def __init__(self, func):
        print("ClassDecoratorA init")
        self.func = func

    def __call__(self, *args, **kwargs):
        print("ClassDecoratorA Call")
        return self.func(*args, **kwargs)


@ClassDecoratorA
def func_cls(a):
    print("func_cls")
    return a


func_cls(1)
print("-------------")


@func_decorator_a
@ClassDecoratorA
def func_cls_decorator(a):
    print("func_cls_decorator")
    return a


func_cls_decorator(1)
print("-------------")


# decorator with parameters
def decorator_with_params(param):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            print(f"decorator_with_params: {param}")
            return func(*args, **kwargs)

        return wrapper

    return decorator


@decorator_with_params("TEST")
def func_with_params(a):
    print("func_with_params")
    return a


func_with_params(0)
print("-------------")

from abc import abstractmethod, ABC


class CLSWithDecoratorFunc(ABC):
    def __init__(self):
        self._private_attr = 0

    @decorator_with_params("CLASS METHOD")
    def method_a(self, a):
        print("CLSWithDecoratorFunc method_a:{a}")
        return a

    def cls_decorator_b(param):
        def decorator(func):
            @wraps(func)
            def wrapper(self, *args, **kwargs):
                print(f"1 cls_decorator_b: {param},_private_attr: {self._private_attr}")
                self._private_attr = param
                print(f"2 cls_decorator_b: {param},_private_attr: {self._private_attr}")
                return func(self, *args, **kwargs)

            return wrapper

        return decorator

    @cls_decorator_b("CLASS METHOD B")
    def method_b(self, a):
        print(f"1 parent method_b ,_private_attr: {self._private_attr}")
        self._private_attr = a
        print(f"2 parent method_b ,_private_attr: {self._private_attr}")
        return a


class CLSWithDecoratorFuncChild(CLSWithDecoratorFunc):
    def method_b(self, a):
        print(f"1 child method_b ,_private_attr: {self._private_attr}")
        self._private_attr = a
        print(f"2 child method_b ,_private_attr: {self._private_attr}")
        return a


print("\nparent:")
cls_parent = CLSWithDecoratorFunc()
cls_parent.method_a(1)
cls_parent.method_b(2)

print("\nchild:")
cls_child = CLSWithDecoratorFuncChild()
cls_child.method_a(1)
cls_child.method_b(2)
print("-------------")


# default decorator
from abc import abstractmethod
from functools import lru_cache, cached_property, total_ordering, singledispatch


# 通过cache装饰器较少重复计算
@lru_cache(maxsize=128, typed=True)
def fibonacci(n):
    if n < 2:
        return n
    else:
        return fibonacci(n - 1) + fibonacci(n - 2)


@total_ordering  # 实现比较方法,只用实现__eq__和__lt__(或者__gt__)方法，其他自动补全
class AbastractClass:
    def __init__(self, rank):
        self.rank = rank
        pass

    # 额外的构造方法
    @classmethod
    def abstract_classmethod(cls):
        pass

    # 抽象方法，子类必须实现
    @abstractmethod
    def abstract_method(self):
        pass

    # 静态方法，
    @staticmethod
    def static_method():
        pass

    # 属性方法，只读
    @property
    def property_method(self):
        pass

    # 相当于：
    # @property
    # @lru_cache()
    @cached_property
    def property_method_cached(self):
        pass

    @singledispatch
    def func_singledispatch(self, other):
        pass

    @func_singledispatch.register(int)
    def _(data):
        print("int")
        return data

    @func_singledispatch.register(str)
    def _(data):
        print("str")
        return data

    def __eq__(self, other):
        return self.rank == other.rank

    def __lt__(self, other):
        return self.rank < other.rank
